package JUC;

/**
 * wait_notify类用于演示线程间的协作关系，特别是生产者-消费者模型
 * 通过wait()和notifyAll()方法来控制线程的等待与唤醒，以实现资源的生产和消费
 */
public class WaitNotifyDemo {

    /**
     * Resource类代表共享资源，它被生产者和消费者线程所访问
     */
    public static class Resource{
        int num = 0;

        /**
         * 生产方法，当资源不为0时，生产者线程等待；否则生产资源
         * @throws InterruptedException 当线程等待被中断时抛出此异常
         */
        private synchronized void add() throws InterruptedException {
            while (num != 0){
                this.wait();
            }
            num++;
            System.out.println(Thread.currentThread().getName() + "生产了1个资源，" +
                    "资源总数为：" + num);
            this.notifyAll();
        }

        /**
         * 消费方法，当资源为0时，消费者线程等待；否则消费资源
         * @throws InterruptedException 当线程等待被中断时抛出此异常
         */
        private synchronized void sub() throws InterruptedException {
            while (num == 0){
                this.wait();
            }
            num--;
            System.out.println(Thread.currentThread().getName() + "消费了1个资源，" +
                    "资源总数为：" + num);
            this.notifyAll();
        }
    }

    /**
     * 主方法，创建并启动多个生产者和消费者线程，演示它们如何协作
     * @param args 命令行参数
     */
    public static void main(String[] args) {
        Resource resource = new Resource();

        // 创建并启动生产者和消费者线程
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(100);
                    resource.add();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "A").start();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(200);
                    resource.sub();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "B").start();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(300);
                    resource.add();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "C").start();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(700);
                    resource.sub();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "D").start();
    }
}
